home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / c / pthd-0.000 / pthd-0 / pthd-0.7 / include / dce / exc_handling.h next >
Encoding:
C/C++ Source or Header  |  1995-08-16  |  16.2 KB  |  492 lines

  1. /*
  2.  * 
  3.  * (c) Copyright 1991 OPEN SOFTWARE FOUNDATION, INC.
  4.  * (c) Copyright 1991 HEWLETT-PACKARD COMPANY
  5.  * (c) Copyright 1991 DIGITAL EQUIPMENT CORPORATION
  6.  * To anyone who acknowledges that this file is provided "AS IS"
  7.  * without any express or implied warranty:
  8.  *                 permission to use, copy, modify, and distribute this
  9.  * file for any purpose is hereby granted without fee, provided that
  10.  * the above copyright notices and this notice appears in all source
  11.  * code copies, and that none of the names of Open Software
  12.  * Foundation, Inc., Hewlett-Packard Company, or Digital Equipment
  13.  * Corporation be used in advertising or publicity pertaining to
  14.  * distribution of the software without specific, written prior
  15.  * permission.  Neither Open Software Foundation, Inc., Hewlett-
  16.  * Packard Company, nor Digital Equipment Corporation makes any
  17.  * representations about the suitability of this software for any
  18.  * purpose.
  19.  * 
  20.  */
  21. /*
  22.  */
  23. #ifndef EXC_HANDLING_H
  24. #define EXC_HANDLING_H
  25. /*
  26. **
  27. **  NAME:
  28. **
  29. **      exc_handling.h
  30. **
  31. **  FACILITY:
  32. **
  33. **      Exceptions
  34. **
  35. **  ABSTRACT:
  36. ** 
  37. **  Pthread based exception package support header file.
  38. **
  39. **  This header file defines a TRY/CATCH exception mechanism that runs
  40. **  'on top of' P1003.4a/D4 pthreads.
  41. ** 
  42. **  The following implementation models all exceptions by converting them
  43. **  into a "cancel" and counting on pthreads to maintain the cancel cleanup
  44. **  handler chain.  So, rather than really maintain our own exception
  45. **  handler list, we just piggyback on the cancel cleanup handler list
  46. **  at the expense of a slightly more expensive RAISE().  There is a per
  47. **  thread global "current exception" that is set to the exception that
  48. **  is being processed.
  49. ** 
  50. **  Exception handlers execute with general cancellability disabled.
  51. ** 
  52. **  Arbitrary application pthread_cancel(pthread_self()) (i.e. something
  53. **  not part of the exception package; not a RAISE) that are delivered
  54. **  while in the scope of an exception handler will unwind to the exception
  55. **  handler; these "outside" pthread_cancel's are represented as a "cancel"
  56. **  exception.
  57. ** 
  58. */
  59. #include <pthread.h>       /* @@ */
  60. #include <sys/types.h>
  61. #include <setjmp.h>
  62.  
  63. #ifdef __STDC__
  64. #   define _EXCHND_PROTO_(x) x
  65. #else
  66. #   define _EXCHND_PROTO_(x) ()
  67. #endif
  68.  
  69. /* --------------------------------------------------------------------------- */
  70.  
  71. typedef enum _exc_kind_t 
  72. {
  73.     _exc_c_kind_address = 0x02130455,  
  74.     _exc_c_kind_status  = 0x02130456
  75. } _exc_kind_t;
  76.  
  77. typedef struct _exc_exception
  78. {
  79.     _exc_kind_t kind;
  80.     union match_value {
  81.         int                     value;
  82.         struct _exc_exception   *address;       
  83.     } match;
  84. } EXCEPTION;
  85.  
  86. #define EXCEPTION_INIT(e) { \
  87.     (e).kind = _exc_c_kind_address; \
  88.     (e).match.address = &(e); \
  89.     }
  90.  
  91. #define exc_set_status(e, s) ( \
  92.     (e)->match.value = (s), \
  93.     (e)->kind = _exc_c_kind_status \
  94. )
  95.  
  96. extern pthread_key_t _exc_key;
  97.  
  98. /* --------------------------------------------------------------------------- */
  99.  
  100. typedef struct _exc_jmpbuf
  101. {
  102.     unsigned    setcancel;       /* state of general cancel delivery mode */
  103.     unsigned    setasynccancel;  /* state of async cancel delivery mode */
  104.     jmp_buf      jb;
  105. } _exc_jmpbuf;
  106.  
  107. /*
  108.  * An exception handler buffer (state block).
  109.  */
  110. typedef struct _exc_buf
  111. {
  112.     _exc_jmpbuf      jb;
  113. } _exc_buf;
  114.  
  115. /* --------------------------------------------------------------------------- */
  116.  
  117. int exc_matches
  118.     _EXCHND_PROTO_((
  119.         EXCEPTION *cur_exc,
  120.         EXCEPTION *exc
  121.     ));
  122.  
  123. void exc_report
  124.     _EXCHND_PROTO_((
  125.         EXCEPTION *exc
  126.     ));
  127.  
  128. void _exc_thread_init
  129.     _EXCHND_PROTO_((
  130.         void
  131.     ));
  132.  
  133. void _exc_raise
  134.     _EXCHND_PROTO_((
  135.         EXCEPTION *exc
  136.     ));
  137.  
  138. void _exc_cleanup_handler
  139.     _EXCHND_PROTO_((
  140.         _exc_buf *exc_buf
  141.     ));
  142.  
  143. void _exc_setjmp_postlude
  144.     _EXCHND_PROTO_((
  145.         _exc_jmpbuf *jmpbuf
  146.     ));
  147.  
  148. /* --------------------------------------------------------------------------- */
  149.  
  150. /*
  151.  * The following exception is used to report an attempt to raise an
  152.  * uninitialized exception object. It should never be raised by any other
  153.  * code.
  154.  */
  155.  
  156. extern EXCEPTION exc_uninitexc_e;       /* Uninitialized exception */
  157.  
  158. /*
  159.  * The following exceptions are common error conditions which may be raised
  160.  * by the thread library or any other facility following this exception
  161.  * specification.
  162.  */
  163.  
  164. extern EXCEPTION exc_exquota_e;         /* Exceeded quota */
  165. extern EXCEPTION exc_insfmem_e;         /* Insufficient memory */
  166. extern EXCEPTION exc_nopriv_e;          /* No privilege */
  167.  
  168. /*
  169.  * The following exceptions describe hardware or operating system error
  170.  * conditions that are appropriate for most hardware and operating system
  171.  * platforms. These are raised by the exception facility to report operating
  172.  * system and hardware error conditions.
  173.  */
  174.  
  175. extern EXCEPTION exc_illaddr_e;         /* Illegal address */
  176. extern EXCEPTION exc_illinstr_e;        /* Illegal instruction */
  177. extern EXCEPTION exc_resaddr_e;         /* Reserved addressing mode */
  178. extern EXCEPTION exc_privinst_e;        /* Privileged instruction */
  179. extern EXCEPTION exc_resoper_e;         /* Reserved operand */
  180. extern EXCEPTION exc_aritherr_e;        /* Arithmetic error */
  181. extern EXCEPTION exc_intovf_e;          /* Integer overflow */
  182. extern EXCEPTION exc_intdiv_e;          /* Integer divide by zero */
  183. extern EXCEPTION exc_fltovf_e;          /* Floating overflow */
  184. extern EXCEPTION exc_fltdiv_e;          /* Floating divide by zero */
  185. extern EXCEPTION exc_fltund_e;          /* Floating underflow */
  186. extern EXCEPTION exc_decovf_e;          /* Decimal overflow */
  187. extern EXCEPTION exc_subrng_e;          /* Subrange */
  188. extern EXCEPTION exc_excpu_e;           /* Exceeded CPU quota */
  189. extern EXCEPTION exc_exfilsiz_e;        /* Exceeded file size */
  190.  
  191. /*
  192.  * The following exceptions correspond directly to UNIX synchronous
  193.  * terminating signals.  This is distinct from the prior list in that those
  194.  * are generic and likely to have equivalents on most any operating system,
  195.  * whereas these are highly specific to UNIX platforms.
  196.  */
  197.  
  198. extern EXCEPTION exc_SIGTRAP_e;         /* SIGTRAP received */
  199. extern EXCEPTION exc_SIGIOT_e;          /* SIGIOT received */
  200. extern EXCEPTION exc_SIGUNUSED_e;          /* SIGUNUSED received */
  201. extern EXCEPTION exc_SIGIOT_e;          /* SIGIOT received */
  202. extern EXCEPTION exc_SIGPIPE_e;         /* SIGPIPE received */
  203. extern EXCEPTION exc_unksyncsig_e;      /* Unknown synchronous signal */
  204.  
  205. /*
  206.  * The following exception is raised in the target of a cancel
  207.  */
  208.  
  209. extern EXCEPTION pthread_cancel_e;      
  210.  
  211. /*
  212.  * The following aliases exist for backward compatibility with CMA.
  213.  */
  214.  
  215. #define cma_e_alerted           pthread_cancel_e
  216.                                                     
  217. /* --------------------------------------------------------------------------- */
  218.  
  219. /*
  220.  * The following aliases exist for backward compatibility with CMA.
  221.  */
  222.  
  223. #define exc_e_uninitexc         exc_uninitexc_e
  224. #define exc_e_illaddr           exc_illaddr_e
  225. #define exc_e_exquota           exc_exquota_e
  226. #define exc_e_insfmem           exc_insfmem_e
  227. #define exc_e_nopriv            exc_nopriv_e
  228. #define exc_e_illinstr          exc_illinstr_e
  229. #define exc_e_resaddr           exc_resaddr_e
  230. #define exc_e_privinst          exc_privinst_e
  231. #define exc_e_resoper           exc_resoper_e
  232. #define exc_e_SIGTRAP           exc_SIGTRAP_e
  233. #define exc_e_SIGIOT            exc_SIGIOT_e
  234. #define exc_e_SIGUNUSED            exc_SIGUNUSED_e
  235. #define exc_e_aritherr          exc_aritherr_e
  236. #define exc_e_SIGIOT            exc_SIGIOT_e
  237. #define exc_e_SIGPIPE           exc_SIGPIPE_e
  238. #define exc_e_excpu             exc_excpu_e
  239. #define exc_e_exfilsiz          exc_exfilsiz_e
  240. #define exc_e_intovf            exc_intovf_e
  241. #define exc_e_intdiv            exc_intdiv_e
  242. #define exc_e_fltovf            exc_fltovf_e
  243. #define exc_e_fltdiv            exc_fltdiv_e
  244. #define exc_e_fltund            exc_fltund_e
  245. #define exc_e_decovf            exc_decovf_e
  246. #define exc_e_subrng            exc_subrng_e
  247.  
  248. #define exc_e_accvio            exc_e_illaddr
  249. #define exc_e_SIGILL            exc_e_illinstr
  250. #define exc_e_SIGFPE            exc_e_aritherr
  251. #define exc_e_SIGBUS            exc_e_illaddr
  252. #define exc_e_SIGSEGV           exc_e_illaddr
  253. #define exc_e_SIGXCPU           exc_e_excpu
  254. #define exc_e_SIGXFSZ           exc_e_exfilsiz
  255.  
  256. /* --------------------------------------------------------------------------- */
  257.  
  258. /*
  259.  * _ E X C _ S E T J M P / L O N G J M P 
  260.  * 
  261.  * Similar to setjmp(2) and longjmp(2) these macros also save/restore
  262.  * the cancel state of a canceled thread providing a means to "handle"
  263.  * a cancel.
  264.  * 
  265.  * These macros gives us the basic mechanism to create in-line exception
  266.  * handlers (i.e. TRY / CATCH) and integrate the exception package with
  267.  * the pthread cancel mechanism.
  268.  * 
  269.  * _exc_longjmp() must be defined to be legal to use from within a
  270.  * pthread cleanup handler.
  271.  * 
  272.  * Notes:
  273.  *
  274.  * (1) _exc_longjmp() is NOT integrated with pthread cleanup handlers.
  275.  * Specifically, calling _exc_longjmp() will not induce behaviour as
  276.  * if a cancel had been delivered to the thread.  The intent is that
  277.  * _exc_{setjmp,longjmp}() are to be used by exception package developers.
  278.  *
  279.  * (2) cancels must be turned off prior to calling setjmp to set up the
  280.  * jmpbuf for the exception handler.  Therefore the setcancel calls around
  281.  * setjmp are not clearly separable into an exception prelude function.
  282.  */
  283. #ifndef CANCEL_ON
  284. #define CANCEL_ON  ((int) 1)
  285. #define CANCEL_OFF ((int) 0)
  286. #endif
  287.  
  288. #define _exc_setjmp(jmpbuf, i) \
  289.     _exc_thread_init(); \
  290.     (jmpbuf)->setasynccancel = pthread_setasynccancel(CANCEL_OFF); \
  291.     (jmpbuf)->setcancel = pthread_setcancel(CANCEL_OFF); \
  292.     *(i) = _setjmp((jmpbuf)->jb); \
  293.     if( *(i) == 0 ) { \
  294.         if ((jmpbuf)->setcancel != CANCEL_OFF ) \
  295.             pthread_setcancel(CANCEL_ON); \
  296.         if ((jmpbuf)->setasynccancel != CANCEL_OFF) \
  297.             pthread_setasynccancel(CANCEL_ON); \
  298.     } \
  299.     if (*(i) != 0) \
  300.         _exc_setjmp_postlude((_exc_jmpbuf *) jmpbuf)
  301.     
  302. #define _exc_longjmp(jmpbuf, val) _longjmp((jmpbuf)->jb, (val))
  303.        
  304. /* --------------------------------------------------------------------------- */
  305.  
  306. /*
  307.  * T R Y
  308.  *
  309.  * Define the beginning of an exception handler scope and the non-exception
  310.  * code path.
  311.  *
  312.  * - Push a cancel cleanup handler for this exception handler
  313.  * - Arrange it so that this cancel cleanup handler gets us back to this 
  314.  *   code when an exception occurs (_exc_setjmp).
  315.  * - If an exception occurred, get a handle to the thread's "current
  316.  *   exception" value (so CATCH clauses can RERAISE the exception).
  317.  *
  318.  * Note that the rough schema for the exception handler is:
  319.  *
  320.  *      do {
  321.  *          pthread_cleanup_push("routine that will longjmp back here");
  322.  *          val = setjmp(...);
  323.  *          if (val == 0)
  324.  *              ...normal code...
  325.  *          else
  326.  *              ...exception code...
  327.  *          ...finally code...
  328.  *          if ("exception happened")
  329.  *              if ("exception handled")
  330.  *                  break;
  331.  *              else
  332.  *                  ...re-raise exception...
  333.  *          pthread_cleanup_pop(...);
  334.  *      } while (0);
  335.  *
  336.  * Exceptions are raised by doing a pthread_cancel against one's self
  337.  * and then doing a pthread_testcancel.  This causes the topmost cleanup
  338.  * routine to be popped and called.  This routine (_exc_cleanup_handler)
  339.  * longjmp's back to the exception handler.  This approach means we can
  340.  * leverage off the fact that the push/pop routines are maintaining some
  341.  * per-thread state (hopefully [but likely not] more efficiently than
  342.  * we could ourselves).  We need this state to string together the dynamic
  343.  * stack of exception handlers.
  344.  *
  345.  * Most of this trickery is so we can avoid doing the pop in the "exception
  346.  * handled" path (since the cleanup routine will already have been popped).
  347.  * (We also need to keep the push and pop appropriately lexically scoped
  348.  * per the pthread spec.)
  349.  *
  350.  * Note that there's some tricky stuff that deals with the case of an
  351.  * exception being raised in a FINALLY clause that was entered in the
  352.  * normal (i.e., non-exception) case.  The problem is that we haven't
  353.  * yet popped the current cleanup routine so when the exception gets
  354.  * raised, we execute it and longjmp back to the CURRENT exception handler,
  355.  * not the next one.  We deal with this by initializing a flag
  356.  * (_exc_in_finally) to "false" and set it to "true" in the FINALLY clause.
  357.  * If we ever jump back and see the flag is "true", we know we should
  358.  * just re-raise right away.
  359.  */
  360. #define TRY \
  361. do \
  362. { \
  363.     volatile _exc_buf _eb; \
  364.     EXCEPTION *_exc_cur; \
  365.     volatile char _exc_cur_handled = 0; \
  366.     volatile char _exc_in_finally = 0; \
  367.     volatile int _setjmp_res; \
  368.     \
  369.     pthread_cleanup_push((cleanup_t)_exc_cleanup_handler, (void *) &_eb); \
  370.     _exc_setjmp(&_eb.jb, (volatile int *) &_setjmp_res); \
  371.     if (_setjmp_res != 0) \
  372.     { \
  373.         pthread_getspecific(_exc_key, (void *) &_exc_cur); \
  374.         if (_exc_in_finally) \
  375.             _exc_raise(_exc_cur); \
  376.     } \
  377.     if (_setjmp_res == 0) \
  378.     { \
  379.         /* normal code here  */
  380.  
  381. /* --------------------------------------------------------------------------- */
  382.  
  383. /*
  384.  * C A T C H ( e x c )
  385.  *
  386.  * Define the beginning of an exception handler scope for the exception
  387.  * "exc".  The exception handler code must either "fall through" to
  388.  * ENDTRY (indicating that the exception has been handled and to resume
  389.  * execution after the ENDTRY), RERAISE the current exception or RAISE
  390.  * a different exception (in both cases, propagating an unwind to the next
  391.  * higher exception handler).
  392.  */
  393. #define CATCH(exc) \
  394.     } \
  395.     else if (exc_matches(_exc_cur, &(exc))) \
  396.     { \
  397.         _exc_cur_handled = 1; \
  398.         /* exception code here */
  399.  
  400. /*
  401.  * C A T C H _ A L L
  402.  *
  403.  * Define the beginning of an exception handler scope for any exception
  404.  * not explicitly caught by a CATCH(exc).  Everything else is just like
  405.  * CATCH(exc).
  406.  */
  407. #define CATCH_ALL \
  408.     } \
  409.     else \
  410.     { \
  411.         EXCEPTION *THIS_CATCH = _exc_cur; \
  412.         _exc_cur_handled = 1; \
  413.         /* exception code here */
  414.  
  415. /* --------------------------------------------------------------------------- */
  416.  
  417. /*
  418.  * F I N A L L Y
  419.  *
  420.  * Define the beginning of a code block that is to be executed regardless
  421.  * of whether or not an exception occurs.  FINALLY should NOT be used
  422.  * if a CATCH or CATCH_ALL is used.
  423.  */
  424. #define FINALLY \
  425.     } \
  426.     { \
  427.         _exc_in_finally = 1; \
  428.         /* user finally code here */
  429.  
  430. /* --------------------------------------------------------------------------- */
  431.  
  432. /*
  433.  * E N D T R Y
  434.  *
  435.  * Terminate an exception handler scope.
  436.  *
  437.  * We can reach the ENDTRY under several conditions.  Note that we will
  438.  * not reach here if an exception occurred, was caught and was explicitly
  439.  * reraised.
  440.  *
  441.  * If we got here because things went fine (i.e., there was no exception)
  442.  * then we need to pop the cancel cleanup handler and we're done (fall
  443.  * out the bottom).
  444.  *
  445.  * If we got here because an exception occurred AND the exception was
  446.  * NOT handled, we just then we propagate the exception to the next higher
  447.  * exception handler (no need to restore the original cancel state as
  448.  * the induced _exc_longjmp() will reset the state).
  449.  *
  450.  * If we got here because an exception occurred (i.e., the cancel cleanup
  451.  * handler was implicitly popped) AND the exception WAS handled, we just
  452.  * want to break out (NOT do the pop).  Reset the current exception to
  453.  * "cancel" so that we can detect an unwind from outside of the exception
  454.  * package (i.e., via the thread's being cancelled).
  455.  */
  456. #define ENDTRY \
  457.     } \
  458.     if (_setjmp_res != 0) \
  459.     { \
  460.         if (! _exc_cur_handled) \
  461.             _exc_raise(_exc_cur); \
  462.         *_exc_cur = pthread_cancel_e; \
  463.         break; \
  464.     } \
  465.     pthread_cleanup_pop(0); \
  466. } while (0); \
  467. /* End of exception handler scope; continue execution */
  468.  
  469.  
  470. /*
  471.  * R A I S E ( e x c )
  472.  *
  473.  * Raise an exception - i.e. initiate an unwind to the next
  474.  * exception handler.
  475.  */
  476. #define RAISE(exc)  _exc_raise(&exc)
  477.  
  478. /* --------------------------------------------------------------------------- */
  479.  
  480. /*
  481.  * R E R A I S E
  482.  *
  483.  * Raise the current exception - i.e. initiate an unwind to next exception
  484.  * handler.  Note: RERAISE is legal only within a CATCH or a CATCH_ALL.
  485.  * Note _exc_cur may be NULL due to an "outside" pthread_cancel().
  486.  */
  487. #define RERAISE     _exc_raise(_exc_cur)
  488.  
  489. /* --------------------------------------------------------------------------- */
  490.  
  491. #endif
  492.